﻿/**
 * \file CDynMemPool.cc
 * \reversion 0.1
 * \brief 动态内存池，应用于大内存分配的动态内存池]
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */ 
 
#include "CDynMemPool.h"
#include "CUnion.h"
#include "CUnionMember.h"
#include "CStaticMemPool.h"
#include <assert.h>
#include "TestDynMemPool.h"
#include "TestPoolAlloc.h"

/**
 * \brief 构造函数
 */
CDynMemPool::CDynMemPool()
{
	this->m_pFstFreePool = NULL;
	this->m_PoolSize = 0;
	this->m_FreeBlockList.clear();

	/// 注册分配内存的size
	this->Register(sizeof(TestObj));
	this->Register(sizeof(TestObj_1));
	this->Register(sizeof(TestObj_2));
	this->Register(sizeof(TestObj_3));
	this->Register(sizeof(TestObj_4));

	/// 初始化内存池
	this->InitMemPool();
}

/**
 * \brief 析构函数
 */
CDynMemPool::~CDynMemPool()
{
	this->PrintMemBlock();
}

/**
 * \brief 注册
 * \param MemSize：注册的内存大小
 * \retur 注册是否成功
 */
bool CDynMemPool::Register(size_t _MemSize)
{
	/// 大于静态池最大值才允许注册
	if(_MemSize > CStaticMemPool::__MAX_BYTES_)
	{
		//MemBlcGroupNode* pBlcGNode = static_cast<MemBlcGroupNode*>(malloc(sizeof(MemBlcGroupNode)));
		//if(pBlcGNode)
		//{
		//	::new (pBlcGNode) MemBlcGroupNode();

		/// 不在其中，插入
		if(this->m_FreeBlockList.find(_MemSize) == this->m_FreeBlockList.end())
		{
			std::pair<_BLOCK_HASH::_Mylist::iterator, bool> ret_pair;
			ret_pair = this->m_FreeBlockList.insert(std::make_pair(_MemSize, (MemBlcGroupNode*)NULL));
			if(ret_pair.second)
			{
				/// 计算需要的单个最大内存
				this->m_PoolSize = this->m_PoolSize < _MemSize ? _MemSize : this->m_PoolSize;
				return true;
			}
			return false;
		}
		//	return true;
		//}
	}

	return false;
}

/**
 * \brief 初始化
 * \return 是否成功
 */
bool CDynMemPool::InitMemPool()
{
	/// 为内存池分配空间
	this->m_pFstFreePool = static_cast<MemPoolNode*>(malloc(sizeof(MemPoolNode)));

	/// 每块内存池的大小
	size_t allocPoolSize = this->m_PoolSize * __MEM_POOL_MULTIPLE;

	if(this->m_pFstFreePool)
	{
		::new (this->m_pFstFreePool) MemPoolNode();

		/// 内存池首结点分配空间
		this->m_pFstFreePool->_pBeg = static_cast<char*>(malloc(allocPoolSize));
		if(!this->m_pFstFreePool->_pBeg)
		{
			return false;
		}
		::new (this->m_pFstFreePool->_pBeg) char();

		this->m_pFstFreePool->_pFreeBeg = this->m_pFstFreePool->_pBeg;
		this->m_pFstFreePool->_pEnd = this->m_pFstFreePool->_pBeg + allocPoolSize;

		/// 内存池个数
		size_t poolNum = this->m_FreeBlockList.size() * __MEM_POOL_INIT_NUM;

		MemPoolNode* pPool = m_pFstFreePool;

		/// 从第二个结点开始分配
		size_t pos = 0;
		while(pos < poolNum)
		{
			/// 对当前结点的下一个结点分配
			pPool->_pNext = static_cast<MemPoolNode*>(malloc(sizeof(MemPoolNode)));

			if(!pPool->_pNext)
			{
				return false;
			}
			::new (pPool->_pNext) MemPoolNode();

			/// 分配当前结点的下一个结点的内存池
			pPool->_pNext->_pBeg = static_cast<char*>(malloc(allocPoolSize));
			if(!pPool->_pNext->_pBeg)
			{
				return false;
			}

			/// 结束内存地址
			pPool->_pNext->_pEnd = pPool->_pNext->_pBeg + allocPoolSize;
			/// 空闲内存地址开始
			pPool->_pNext->_pFreeBeg = pPool->_pNext->_pBeg;

			pPool->_pNext->_pNext = NULL;

			/// 往下移一个指针
			pPool = pPool->_pNext;

			++pos;
		}

		return true;
	}

	return false;
}

/**
 * \brief 填充内存块
 * \param size：填充的单个内存块大小
 * \param iter：填充目标迭代器
 */
bool CDynMemPool::Refill(size_t size, _BLOCK_ITER& iter)
{
	/// 如果内存池没有内存，分配内存到内存池
	if(!this->m_pFstFreePool)
	{
		this->m_pFstFreePool = static_cast<MemPoolNode*>(malloc(sizeof(MemPoolNode)));
		if(!this->m_pFstFreePool)
		{
			std::cout << "[CDynMemPool]内存池分配失败" << std::endl;
			return false;
		}

		::new (this->m_pFstFreePool) MemPoolNode();

		/// 分配结点中的内存池内存
		this->m_pFstFreePool->_pBeg = static_cast<char*>(malloc(this->m_PoolSize * __MEM_POOL_MULTIPLE));
		if(!this->m_pFstFreePool->_pBeg)
		{
			return false;
		}

		this->m_pFstFreePool->_pFreeBeg = this->m_pFstFreePool->_pBeg;
		this->m_pFstFreePool->_pEnd = this->m_pFstFreePool->_pBeg + this->m_PoolSize * __MEM_POOL_MULTIPLE;
	}

	/// 把第一个空闲内存池块挂到当前块内存组的内存池指针上

	/// 第一个空闲内存池结点
	MemPoolNode* pMPoolNode = this->m_pFstFreePool;
	/// 空闲内存池结点向下移一个
	this->m_pFstFreePool = this->m_pFstFreePool->_pNext;

	/// 新建一个内存块组结点
	MemBlcGroupNode* pNewBGNode = static_cast<MemBlcGroupNode*>(malloc(sizeof(MemBlcGroupNode)));
	if(!pNewBGNode)
	{
		return false;
	}
	::new (pNewBGNode) MemBlcGroupNode();

	/// 新内存块组指向新的空闲内存池
	pNewBGNode->_pMemPool = pMPoolNode;
	/// 挂接到第一个内存块组上
	pNewBGNode->_pNext = iter->second;
	iter->second = pNewBGNode;

	/// 得到内存池可以分成多少个内存块
	size_t maxNum = __MEM_POOL_FREE_SIZE(pMPoolNode) / size;
	size_t pos = 0;

	/// 循环分块
	for(; pos < maxNum; ++pos)
	{
		/// 要插入的内存块结点从组内存池中得到
		MemBlcNode* pInsert = (MemBlcNode*)(static_cast<void*>(pMPoolNode->_pFreeBeg + pos * size));
		/// 下一个内存块设置为当前第一个空闲内存块
		pInsert->_pFreeListLink = pNewBGNode->_pFreeMemBloc;
		/// 设置插入的内存块为第一块空闲内存块
		pNewBGNode->_pFreeMemBloc = pInsert;
	}

	return true;
}

/**
 * \brief 申请内存是否在此范围之内
 * \param _size：申请大小
 * \return 能否申请
 */
bool CDynMemPool::CanAlloc(size_t _size)
{
	return (this->m_FreeBlockList.find(_size) != this->m_FreeBlockList.end());
}

/**
 * \biref 申请一段内存
 * \param _size：申请内存大小
 * \return 返回内存首地址
 */
void* CDynMemPool::Allocate(size_t _size)
{
	_BLOCK_ITER iter = this->m_FreeBlockList.find(_size);
	if(iter != this->m_FreeBlockList.end())
	{
		MemBlcNode* pMemBlc = NULL;
		/// 查找是否有可用内存块
		MemBlcGroupNode* pBGNode = iter->second;
		while(pBGNode)
		{
			if(pBGNode->_pFreeMemBloc)
			{
				/// 找到则跳出
				pMemBlc = pBGNode->_pFreeMemBloc;
				break;
			}

			/// 每次向下长一个结点
			pBGNode = pBGNode->_pNext;
		}

		/// 没有一块可用的内存块，调用Refill填充新的内存池
		if(!pMemBlc && this->Refill(_size, iter))
		{
			/// 填充成功，第一个内存块组的第一个内存块一定是空闲内存块
			pBGNode = iter->second;
		}

		/// 找到内存块组
		if(pBGNode && pBGNode->_pFreeMemBloc)
		{
			/// 内存块
			pMemBlc = pBGNode->_pFreeMemBloc;
			/// 分配完成的内存块移出
			pBGNode->_pFreeMemBloc = pBGNode->_pFreeMemBloc->_pFreeListLink;
			/// 引用计数
			++pBGNode->_pMemPool->_count;
		}

		/// 返回给用户
		return pMemBlc->_ClientData;
	}

	return NULL;
}

/**
 * \brief 释放一段内存
 * \param p：释放内存指针
 * \param _size：内存指针大小
 */
bool CDynMemPool::Deallocate(void *p, size_t _size)
{
	if(!p)
	{
		return false;
	}

	_BLOCK_ITER iter = this->m_FreeBlockList.find(_size);
	if(iter != this->m_FreeBlockList.end())
	{
		MemBlcGroupNode* pPreNode = NULL;

		/// 寻找要释放内存在哪个组中
		MemBlcGroupNode* pBGNode = iter->second;
		while(pBGNode)
		{
			/// 找到
			/// if(__CHECK_MEM_IN_POOL(p, pBGNode->_pMemPool))
			if(p >= pBGNode->_pMemPool->_pBeg && p <= pBGNode->_pMemPool->_pEnd)
			{
				/// 插入此内存块到第一个结点
				MemBlcNode* pInsert = static_cast<MemBlcNode*>(p);
				pInsert->_pFreeListLink = pBGNode->_pFreeMemBloc;
				pBGNode->_pFreeMemBloc = pInsert;

				/// 引用计数结束
				assert(pBGNode->_pMemPool->_count);
				--(pBGNode->_pMemPool->_count);

				/// 如果引用计数为0，说明内存全部归还，释放内存池到公用内存池
				if(!pBGNode->_pMemPool->_count)
				{
					/// 没有上一个，说明是第一个
					if(!pPreNode)
					{
						/// 指向下一个
						iter->second = iter->second->_pNext;
					}
					else
					{
						pPreNode->_pNext = pBGNode->_pNext;
					}

					/// 把内存池还回公用内存池，也就是插入到第一个结点
					pBGNode->_pMemPool->_pFreeBeg = pBGNode->_pMemPool->_pBeg;
					pBGNode->_pMemPool->_pNext = this->m_pFstFreePool;
					this->m_pFstFreePool = pBGNode->_pMemPool;

					/// 释放内存块组结点内存
					free(pBGNode);
				}
				return true;
			}
			pPreNode = pBGNode;
			pBGNode = pBGNode->_pNext;
		}
	}

	return false;
}

/**
 * \brief 打印各个内存块的使用情况，关机程序时，打印可查询内存泄露
 */
void CDynMemPool::PrintMemBlock()
{
	size_t count = 0;
	size_t size = 0;

	std::cout << "【CDynMemPool_MemLookUp】内存块组内存池中内存使用信息：" << std::endl;
	_BLOCK_ITER iter = this->m_FreeBlockList.begin();
	for(; iter != this->m_FreeBlockList.end(); ++iter)
	{
		count = 0;

		if(iter->second)
		{
			MemPoolNode* pPoolNode = iter->second->_pMemPool;
			while(pPoolNode)
			{
				count += pPoolNode->_count;
				size += pPoolNode->_pBeg - pPoolNode->_pEnd;
				pPoolNode = pPoolNode->_pNext;
			}
		}
		std::cout << "	[" << iter->first << "] 未释放内存数量：" << count << std::endl;
	}

	count = 0;
	MemPoolNode* pPoolNode = this->m_pFstFreePool;
	while(pPoolNode)
	{
		count += pPoolNode->_count;
		size += pPoolNode->_pEnd - pPoolNode->_pBeg;
		pPoolNode = pPoolNode->_pNext;
	}
	std::cout << "【CDynMemPool_MemLookUp】公共内存池中未释放内存数量：" << count << std::endl;
	std::cout << "【CDynMemPool_MemLookUp】所有内存池内存数量：" << size << std::endl;
}

/**
 * \brief 检查内存块组所有结点
 */
void CDynMemPool::LookUpMemBlcGroupNode(size_t _size)
{
	static size_t pos = 0;
	pos = 0;
	_BLOCK_ITER iter = this->m_FreeBlockList.find(_size);
	if(iter != this->m_FreeBlockList.end())
	{
		MemBlcGroupNode* beg = iter->second;
		while(beg)
		{
			if((unsigned int)beg == 0xfeeefeee)
			{
				std::cout << "Error!!" << std::endl;
				return;
			}
			++pos;
			beg = beg->_pNext;
		}
	}
}
